#pragma once

#include "curl_response.h"

#include <curl/curl.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

class CurlHttpClient
{
    typedef void(DataCallback)(const char *, size_t, void *);
    struct WriteFuncUserData {
        CURL         *curl            = nullptr;
        void         *resp            = nullptr;
        DataCallback *callback        = nullptr;
        std::string   boundary        = "";
        char         *buffer          = nullptr;
        int           buffer_size     = 0;
        int           buffer_capacity = 0;
    };

public:
    CurlHttpClient();
    ~CurlHttpClient();

public:
    /**
     * @brief 创建 http 头
     *
     * @param property
     * @return std::shared_ptr<curl_slist>
     */
    std::shared_ptr<curl_slist> createHeaders(std::vector<std::string> &&property);
    std::shared_ptr<curl_slist> createHeaders(const std::vector<std::string> &property);

    /**
     * @brief Get the Method object
     *
     * @param url 请求地址
     * @param headers
     * @param res 应答消息
     * @return true
     * @return false
     */
    bool getMethod(CurlResponse &res, const std::string &url, const curl_slist *headers);

    /**
     * @brief post方法发送数据
     *
     * @param url 请求地址
     * @param headers HTTP头
     * @param req 请求消息
     * @param res 应答消息
     * @return true
     * @return false
     */
    bool postMethod(CurlResponse &res, const std::string &url, const curl_slist *headers, const std::string &req);

    /**
     * @brief HTTP长连接获取数据
     *
     * @param url
     * @param headers
     * @param callback
     * @param args
     * @param errmsg
     * @param curlauth
     * @param userpwd
     * @return true
     * @return false
     */
    bool getMethodMultipart(const std::string &url,
                            const curl_slist  *headers,
                            DataCallback      *callback,
                            void              *args,
                            std::string       &errmsg,
                            int                curlauth = CURLAUTH_NONE,
                            std::string        userpwd  = "");

private:
    static int    headerProcess(std::unordered_map<std::string, std::string> &headers, const std::string &header_str);
    static size_t multipartHeaderCB(void *contents, size_t size, size_t nmemb, void *stream);
    static size_t multipartWriteCB(void *contents, size_t size, size_t nmemb, void *stream);
    static size_t receiveCB(void *contents, size_t size, size_t nmemb, void *stream);
};